package ch.gislb2.parallaXis.verSDK10;

import ch.gislb2.parallaXis.verSDK10.exceptions.IntegratorException;
import ch.gislb2.parallaXis.verSDK10.interf.Integrator;

/**
* The Integrator is used to silence the noisy sensors. It is programmed to
* integrate over any-amount sampleSets. If the difference of the amplitude of
* the integration and newest sample is beyond a certain threshold, the
* integration is discarded. (usually this situation occurs if some real change
* is made to the sensor device.
*
* In this implementation a 'Ring-Array' is used to continuously add and remove
* data without having to (de-)allocate memory.
*
* Complexity: Average calculation: O(1) Add / Remove sample: O(1) Clear
* Ring-Array: O(1)
*
* @author SimpliX
*
*/
public class DigitalStabilizerOriginal implements Integrator {
   private final int[] buffer;
   private int first;
   private int last;
   private int actualBufferSize = 0;
   private int average;
   private int sum;
   private int maxNoiseError;
   private int lastValue;

   public DigitalStabilizerOriginal(final int bufferSize, final int maxNoiseError) throws IntegratorException {
       if (bufferSize < 1) {
           throw new IntegratorException("BufferSize too small");
       }
       this.buffer = new int[bufferSize];
       this.setMaxNoiseError(maxNoiseError);
   }

   /**
    * @see ch.simplix.android.zero.integrator.implementation.Integrator#setMaxNoiseError(int)
    */
   public synchronized void setMaxNoiseError(final int maxNoiseError) throws IntegratorException {
       if (maxNoiseError < 0) {
           throw new IntegratorException("Error cannot be smaller than 0");
       }
       this.maxNoiseError = maxNoiseError;
   }

   /**
    * @see ch.simplix.android.zero.integrator.implementation.Integrator#addSample(float)
    */
   public synchronized void addSample(final float value) {
       this.addSample(Math.round(value));
   }

   /**
    * @see ch.simplix.android.zero.integrator.implementation.Integrator#addSample(int)
    */
   public synchronized void addSample(final int value) {
       if (Math.abs(Math.abs(value) - Math.abs(this.getAverage())) > this.maxNoiseError) {
           this.clear();
       }
       this.lastValue = this.buffer[this.last];
       this.buffer[this.last] = value;
       this.sum += value;
       this.last = (this.last + 1) % this.buffer.length;
       if (this.first != this.last) {
           this.actualBufferSize++;
       } else {
           this.first = (this.last + 1) % this.buffer.length;
           this.sum -= this.lastValue;
       }

   }

   /**
    * @see ch.simplix.android.zero.integrator.implementation.Integrator#clear()
    */
   public synchronized void clear() {
       this.first = this.last;
       this.actualBufferSize = 0;
       this.sum = 0;
       this.average = 0;
   }

   /**
    * @see ch.simplix.android.zero.integrator.implementation.Integrator#getAverage()
    */
   public synchronized int getAverage() {
       if (this.actualBufferSize > 0) {
           this.average = this.sum / this.actualBufferSize;
       }
       return this.average;
   }
}
